#include<stdio.h>
#include<iostream>
#include<pthread.h>
#include<queue>


//实现生产者与消费者模型
//首先需要创建一个线程安全等待队列

#define MAX_QUEUE 5   //队列最大容量


template<class T>
class BlockQueue{
private:
  std::queue<T> _q;   //创建一个队列
  int _capacity;      //队列容量
  pthread_mutex_t _mutex;  //互斥锁
  pthread_cond_t _cond_pro;  //生产者条件变量
  pthread_cond_t _cond_con;  //消费者条件变量

public:
  BlockQueue(int capacity = MAX_QUEUE):_capacity(capacity){
    //构造函数:进行互斥锁、条件变量的初始化
    pthread_mutex_init(&_mutex,NULL);
    pthread_cond_init(&_cond_pro,NULL);
    pthread_cond_init(&_cond_con,NULL);
  }
  ~BlockQueue(){
     //析构函数:进行互斥锁，条件变量的销毁
     pthread_mutex_destroy(&_mutex);
     pthread_cond_destroy(&_cond_pro);
     pthread_cond_destroy(&_cond_con);
   }

   bool Push(const T& data){
     //生产者实现数据入队操作
     pthread_mutex_lock(&_mutex);
     while(_capacity==_q.size()){
        //队列中数据满了，需要阻塞生产者
        pthread_cond_wait(&_cond_pro,&_mutex);
      }
     //否则，进行数据入队
     _q.push(data);
     //入队之后，唤醒消费者来取数据，并进行解锁
     pthread_cond_signal(&_cond_con);
     pthread_mutex_unlock(&_mutex);
   }
   
   bool Pop(T *data){
    //消费者获取数据，出队操作
    pthread_mutex_lock(&_mutex);
    while(_q.empty()){
       //队列为空，则阻塞消费者
       pthread_cond_wait(&_cond_con,&_mutex);
    }
    //否则，消费者获取数据 -- 出队
    *data=_q.front();
    _q.pop();
   //唤醒生产者入队数据，并进行解锁操作
   pthread_cond_signal(&_cond_pro);
   pthread_mutex_unlock(&_mutex);
   }

};

int data=0; //定义入队数据
void* Productor(void* arg)
{
  BlockQueue<int>* q=(BlockQueue<int>*)arg;
  while(1){
      //生产者入队数据
     q->Push(data);
     printf("----%p 入队了数据 %d\n",pthread_self(),data++);
  }
  return NULL;
}

void* Consumer(void* arg)
{
  BlockQueue<int>* q=(BlockQueue<int>*)arg;
  while(1){
      //消费者获取数据
      int data;
      q->Pop(&data);
      printf("++++%p 出队了数据 %d\n",pthread_self(),data);
  }
  return NULL;
}

#define MAX_USER 4   //角色个数

int main()
{
  BlockQueue<int> q;  //定义一个线程安全等待队列
  //定义多个生产者线程，多个消费者线程
  pthread_t pro_tid[MAX_USER],con_tid[MAX_USER];
  int ret;
  for(int i=0;i<MAX_USER;++i){
    ret=pthread_create(&pro_tid[i],NULL,Productor,(void*)&q);
    if(ret!=0){
      std::cout<<"pthread_create error\n";
      return -1;
    }
    ret=pthread_create(&con_tid[i],NULL,Consumer,(void*)&q);
    if(ret!=0){
      std::cout<<"pthread_create error\n";
      return -1;
    }
  }

  //线程等待
  for(int i=0;i<MAX_USER;++i){
    pthread_join(con_tid[i],NULL);
    pthread_join(pro_tid[i],NULL);
  }

  return 0;
}











